package com.jf.anmocker.plugin.transform

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import com.jf.anmocker.plugin.injector.AMInjector
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
import java.io.File
import java.io.IOException
import java.util.function.Consumer

class AMTransformKt(project: Project) : Transform() {

    private var project: Project? = null
    private var injector: AMInjector? = null
    private val INJECT_JAR = false

    init {
        this.project = project
        injector = AMInjector(project)
        printCopyRight()
    }

    // 指定 Transform 的名称，该名称还会用于组成 Task 的名称
    // 格式为 transform[InputTypes]With[name]For[Configuration]
    override fun getName(): String {
        return "TransformKtWithInjector"
    }

    /**
     * 需要处理的数据类型，有两种枚举类型
     * CLASSES 代表处理的 java 的 class 文件，RESOURCES 代表要处理 java 的资源
     * @return
     */
    override fun getInputTypes(): Set<QualifiedContent.ContentType?>? {
        return TransformManager.CONTENT_CLASS
    }

    /**
     * 指 Transform 要操作内容的范围，官方文档 Scope 有 7 种类型：
     * 1. EXTERNAL_LIBRARIES        只有外部库
     * 2. PROJECT                   只有项目内容
     * 3. PROJECT_LOCAL_DEPS        只有项目的本地依赖(本地jar)
     * 4. PROVIDED_ONLY             只提供本地或远程依赖项
     * 5. SUB_PROJECTS              只有子项目。
     * 6. SUB_PROJECTS_LOCAL_DEPS   只有子项目的本地依赖项(本地jar)。
     * 7. TESTED_CODE               由当前变量(包括依赖项)测试的代码
     * @return
     */
    override fun getScopes(): MutableSet<in QualifiedContent.Scope>? {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    // 指定是否支持增量编译
    override fun isIncremental(): Boolean {
        return false
    }

    /**
     * 打印提示信息
     */
    private fun printCopyRight() {
        println()
        println("####################################################################")
        println("########                                                    ########")
        println("########                                                    ########")
        println("########              欢迎使用 AnMockerK 编译插件              ########")
        println("########              使用过程中碰到任何问题请联系我们            ########")
        println("########                                                     ########")
        println("########                                                     ########")
        println("#####################################################################")
        println()
    }

    override fun transform(transformInvocation: TransformInvocation?) {
        super.transform(transformInvocation)
    }

    // 核心 API
    @Throws(
        IOException::class,
        TransformException::class,
        InterruptedException::class
    )
    override fun transform(
        context: Context?, inputs: Collection<TransformInput>,
        referencedInputs: Collection<TransformInput?>?,
        outputProvider: TransformOutputProvider,
        isIncremental: Boolean
    ) {
        //增量判断
        if (!isIncremental) {
            outputProvider.deleteAll()
        }
        println("---------- transform from MyTransformK !---------$isIncremental")
        // Transform 的 inputs 有两种类型，一种是目录，一种是 jar 包，要分开遍历
        inputs.forEach(Consumer { input: TransformInput ->
            //遍历JAR
            readJarInputs(outputProvider, input.jarInputs)
            //遍历目录
            readDirectoryInputs(outputProvider, input.directoryInputs)
        })
    }

    private fun readDirectoryInputs(
        outputProvider: TransformOutputProvider,
        directoryInputs: Collection<DirectoryInput>
    ) {
        //println("Transform directoryInputs start.")
        val outPutList = mutableListOf<TransformEntity>()
        //扫描文件
        directoryInputs.forEach(Consumer { directoryInput: DirectoryInput ->
            //遍历开始
            //println("directoryInputs >>> " + directoryInput.file.absolutePath)
            //处理文件类
            injector?.collectClassFileFromDir(directoryInput.file)
            //获取 output 目录
            val dest = outputProvider.getContentLocation(
                directoryInput.name,
                directoryInput.contentTypes, directoryInput.scopes,
                Format.DIRECTORY
            )
            outPutList.add(TransformEntity(directoryInput.file, dest))
        })
        //注入处理文件
        injector?.injectCollectClasses()
        //输出文件
        outPutList.forEach {
            try {
                println("copyDirectory >>> ${it.dest}")
                //将 input 的目录复制到 output 指定目录
                FileUtils.copyDirectory(it.inputFile, it.dest)
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    private fun readJarInputs(
        outputProvider: TransformOutputProvider,
        jarInputS: Collection<JarInput>
    ) {
        //println("Transform jarInputs start.")
        jarInputS.forEach(Consumer { jarInput: JarInput ->
            if(INJECT_JAR){
                injectJars(outputProvider, jarInput)
            }else{
                readJars(outputProvider, jarInput)
            }
        })
    }

    private fun readJars(outputProvider: TransformOutputProvider, jarInput: JarInput){
        val copyJarFile = jarInput.file
        //不做任何改变输出
        val dest = outputProvider.getContentLocation(
            jarInput.name,
            jarInput.contentTypes,
            jarInput.scopes,
            Format.JAR
        )
        // 将 input 的目录复制到 output 指定目录
        try {
            FileUtils.copyFile(copyJarFile, dest)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    private fun injectJars(outputProvider: TransformOutputProvider, jarInput: JarInput){
        /**重命名输出文件（同目录copyFile会冲突） */
        var destName = jarInput.file.name
        //遍历开始
        println("jarInputs >>> $destName")
        /**截取文件路径的 md5 值重命名输出文件,因为可能同名,会覆盖 */
        val hexName =
            DigestUtils.md5Hex(jarInput.file.absolutePath)
                .substring(0, 8)
        /** 获取 jar 名字 */
        if (destName.endsWith(".jar")) {
            destName = destName.substring(0, destName.length - 4)
        }
        //不做任何改变输出
        val copyJarFile = jarInput.file
        if (INJECT_JAR) {
            injector?.collectClassFileFromJar(jarInput.file)
            //更新内容
            //File copyJarFile = MyJarAnalyticsInjectG.injectJar(jarInput.getFile().getAbsolutePath(), project);
        }
        ////生成输出路径
        //File dest = outputProvider.getContentLocation(destName + hexName,
        //        jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR);
        //生成输出路径
        val dest = outputProvider.getContentLocation(
            destName + hexName,
            jarInput.contentTypes,
            jarInput.scopes,
            Format.JAR
        )
        // 将 input 的目录复制到 output 指定目录
        try {
            FileUtils.copyFile(copyJarFile, dest)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    // 指定是否支持缓存
    override fun isCacheable(): Boolean {
        return false
    }
}

data class TransformEntity(var inputFile : File,var dest : File)